package com.linkoog.devtools.everywhere.docs;

import com.google.gson.Gson;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NotNullLazyKey;

import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.event.HyperlinkEvent;

import org.apache.commons.compress.utils.IOUtils;
import org.jetbrains.annotations.NotNull;

public final class SearchTitlesProvider {

    public static final NotificationGroup BALLOON_NOTIFICATIONS = NotificationGroup.balloonGroup("Doc-Aware Search Everywhere Balloons");
    public static final NotNullLazyKey<SearchTitlesProvider, Project> INSTANCE_CACHE = ServiceManager.createLazyKey(SearchTitlesProvider.class);
    private static final String PREFIX = "https://www.jetbrains.com/help/";
    private static final String URL_PATTERN = "https://www.jetbrains.com/help/{0}/{1}/{2}";
    private boolean ready;
    private final Project project;
    private final String productWebPath;
    private final String productWebVersion;
    private boolean loading;
    private final Map<String, TitleInfo> items;

    private SearchTitlesProvider(@NotNull Project project) {
        this.ready = false;
        this.loading = false;
        this.items = new HashMap();
        this.project = project;

        ApplicationNamesInfo nameInfo = ApplicationNamesInfo.getInstance();
        String edition = nameInfo.getEditionName();
        String name = nameInfo.getProductName().toLowerCase();

        switch (name) {
            case "rubymine":
            case "ruby":
                this.productWebPath = "ruby";
                break;
            case "intellij idea":
            case "idea":
                this.productWebPath = "idea";
                break;
            case "goland":
                this.productWebPath = "go";
                break;
            case "appcode":
                this.productWebPath = "objc";
                break;
            case "pycharm":
                this.productWebPath = (edition != null && edition.toLowerCase().equals("edu")) ? "pycharm-edu" : "pycharm";
                break;
            default:
                this.productWebPath = name;
                break;
        }
        this.productWebVersion = ApplicationInfo.getInstance().getMajorVersion() + "." + ApplicationInfo.getInstance().getMajorVersion();
    }


    @NotNull
    public static SearchTitlesProvider getInstance(@NotNull Project project) {
        return INSTANCE_CACHE.getValue(project);
    }


    @NotNull
    public Map<String, TitleInfo> getItems() {
        if (this.ready) {
            return Collections.unmodifiableMap(this.items);
        }

        if (!this.loading) {
            BALLOON_NOTIFICATIONS.createNotification("Doc-Aware Search", null, "Cache for " +
                    ApplicationNamesInfo.getInstance().getFullProductName() + " is not ready, attempting to load now.", NotificationType.WARNING, (notification, event) ->
                    load())
                    .notify(this.project);
            ApplicationManager.getApplication().executeOnPooledThread(this::load);
        }

        return Collections.emptyMap();
    }


    public boolean isReady() {
        return this.ready;
    }


    public void load() {
        if (!this.loading) {
            this.loading = true;
            try {
                InputStream stream = (new URL(MessageFormat.format("https://www.jetbrains.com/help/{0}/{1}/{2}", new Object[]{this.productWebPath, this.productWebVersion, "title-indexes.json"}))).openStream();
                try {
                    for (FileIndex info :  (new Gson()).fromJson(new String(IOUtils.toByteArray(stream), StandardCharsets.UTF_8), FileIndex[].class)) {
                        TitleInfo main = new TitleInfo(info.title, info.file, "", info.title, "topic", MessageFormat.format("https://www.jetbrains.com/help/{0}/{1}/{2}", new Object[]{this.productWebPath, this.productWebVersion, info.file}));

                        this.items.put(main.toString(), main);
                        if (info.sections != null) {
                            info.sections.forEach(sectionInfo -> {
                                TitleInfo section = new TitleInfo(sectionInfo.title, info.file, (sectionInfo.anchor == null) ? "" : sectionInfo.anchor, info.title, sectionInfo.type, MessageFormat.format("https://www.jetbrains.com/help/{0}/{1}/{2}", new Object[]{this.productWebPath, this.productWebVersion, info.file + info.file}));
                                this.items.put(section.toString(), section);
                            });
                        }
                    }
                    this.ready = true;
                    BALLOON_NOTIFICATIONS.createNotification("Doc-Aware Search", null, "Cache for " +
                            ApplicationNamesInfo.getInstance().getFullProductName() + " is ready.", NotificationType.INFORMATION)
                            .notify(this.project);
                    if (stream != null) stream.close();
                } catch (Throwable throwable) {
                    if (stream != null) {
                        try {
                            stream.close();
                        } catch (Throwable throwable1) {
                            throwable.addSuppressed(throwable1);
                        }
                    }
                    throw throwable;
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                this.loading = false;
            }

        }
    }


    public static class FileIndex {
        String file;
        String title;
        List<SectionIndex> sections;
    }


    public static class SectionIndex {
        String title;
        String anchor;
        String type;
    }


    public static class TitleInfo {
        String title;
        String fileName;
        String anchor;
        String articleTitle;
        String type;
        String url;

        public TitleInfo(String title, String fileName, String anchor, String articleTitle, String type, String url) {
            this.title = title;
            this.fileName = fileName;
            this.anchor = anchor;
            this.articleTitle = articleTitle;
            this.type = type;
            this.url = url;
        }


        public TitleInfo() {
        }


        public String toString() {
            return this.title + " " + this.title + " " + this.articleTitle;
        }
    }
}
